package xquery;

import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Map;

import org.apache.xerces.parsers.DOMParser;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

public class XPathSimpleExp extends XPathExp {
	public enum XPathNodeType {
		DOC, TAG, CURRENT, PARENT, ANY, TEXT;
		
		public static XPathNodeType string2type(String s) {
			if(s.equals("."))
				return CURRENT;
			else if(s.equals(".."))
				return PARENT;
			else if(s.equals("*"))
				return ANY;
			else
				assert(false);
			
			return null;
		}
	}
	
	XPathNodeType type;
	String value;
	
	@Override
	public XPathData eval(XQContext context, ArrayList<Node> currentNodeList) {
		XPathData result = new XPathData();
		switch(type) {
		case DOC:
			result.set(setDoc(context));
			break;
		case TAG:
			result.set(evalTag(context, currentNodeList));
			break;
		case ANY:
			result.set(evalAny(context, currentNodeList));
			break;
		case CURRENT:
			result.set(currentNodeList);
			break;
		case PARENT:
			result.set(evalParent(context, currentNodeList));
			break;
		case TEXT:
			result.set(evalText(context, currentNodeList));
			break;
		default:
			assert(false);
			return null;
		}
		
		return result;
	}
	
	private ArrayList<Node> setDoc(XQContext context) {
		ArrayList<Node> currentNodeList = new ArrayList<Node>();
		Map<String, Document> currentDocs = context.getCurrentDocs();
		Document doc = null;
		
		String filename = value.substring(1, value.length()-1);
		
        try {
        	if(!currentDocs.containsKey(filename))
        	{
        		FileInputStream inputfile = new FileInputStream(filename);
	        	DOMParser p = new DOMParser();
				p.parse(new InputSource(inputfile));		
		        doc = p.getDocument();
		        currentDocs.put(filename, doc);
		        inputfile.close();
        	}
        	else
        	{
        		doc = currentDocs.get(filename);
        	}
	        Node root  = doc.getDocumentElement();   
	        currentNodeList.add(root);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return currentNodeList;
	}
	
	private ArrayList<Node> evalTag(XQContext context, ArrayList<Node> currentNodeList)
	{
		ArrayList<Node> resultNodeList = new ArrayList<Node>();
		for(Node node:currentNodeList)
		{
			if(node instanceof XQueryNode)
			{
				ArrayList<Node> children = ((XQueryNode)node).childList;
				for(Node child : children)
				{
					if(child.getNodeType() == Node.ELEMENT_NODE)
					{
						if(child.getNodeName().equals(value))
						{
							resultNodeList.add(child);
						}
					}					
				}
			}
			else
			{
				Node child = node.getFirstChild();
				while(child != null)
				{
					if(child.getNodeType() == Node.ELEMENT_NODE)
					{
						if(child.getNodeName().equals(value))
						{
							resultNodeList.add(child);
						}
					}
					child = child.getNextSibling();
				}
			}
		}

		return resultNodeList;
	}
	
	private ArrayList<Node> evalAny(XQContext context, ArrayList<Node> currentNodeList)
	{
		ArrayList<Node> resultNodeList = new ArrayList<Node>();

		NodeList children = null;
		Node child;
		for(Node node:currentNodeList)
		{
			children = node.getChildNodes();
			for (int i = 0; i< children.getLength(); i++)
			{
				child = children.item(i);
				resultNodeList.add(child);
			}
		}
		return resultNodeList;
	}
	
	private ArrayList<Node> evalParent(XQContext context, ArrayList<Node> currentNodeList)
	{
		ArrayList<Node> resultNodeList = new ArrayList<Node>();
		Node parent = null;
		for(Node node: currentNodeList)
		{		
			parent = node.getParentNode();
			if(parent != null)
			{
				resultNodeList.add(parent);
			}
		}
		return resultNodeList;
	}
	
	private ArrayList<Node> evalText(XQContext context, ArrayList<Node> currentNodeList)
	{
		ArrayList<Node> resultNodeList = new ArrayList<Node>();
		Node child = null;
		for(Node node:currentNodeList)
		{
			child = node.getFirstChild();
			while(child != null)
			{
				if(child.getNodeType() == Node.TEXT_NODE)
				{
					resultNodeList.add(child);
				}
				child = child.getNextSibling();
			}
		}
		return resultNodeList;
	}
	public String toString()
	{
		
		switch(type) {
		case DOC:
			return "doc(" + value +")";
		case TAG:
			return value;
		case TEXT:
			return "text()";
		}
		return null;		
	}
}
